#include "remm_utils.h"

lsv_s32_t remm_conf_load(lsv_volume_proto_t *volume_proto){
        lsv_s32_t err = 0;
        config_t cfg;
	lsv_remm_info * remm_info = NULL;
	lsv_s8_t * buf;
	lsv_s8_t * buf_prt1;
	char host[256];
	lsv_s32_t data;
	DINFO("enter ....\n");
        config_init(&cfg);
        if(!config_read_file(&cfg, LSV_REMM_CONF_FILE)){
                DERROR("config_read_file %s ERROR!\tline: %d\t%s\n", LSV_REMM_CONF_FILE, cfg.error_line, cfg.error_text);
                err = -1;
                goto EXIT;
        }

	remm_info = (lsv_remm_info *)malloc(sizeof(lsv_remm_info));
	if(NULL == remm_info){
		err = -ENOMEM;
		DERROR("malloc for lsv_remm_info failed\n");
		goto EXIT;
	}
	memset(remm_info, 0, sizeof(lsv_remm_info));

#if 1	
	if(!config_lookup_string(&cfg, LSV_REMM_CLUSTER_PAIR_STRING, &buf)){
		err = -errno;
		DERROR("config lookup LSV_REMM_ID failed\n");	
		goto EXIT;
        }
	buf_ptr = strchr(buf, ':');
	if(NULL == buf_ptr){
		err = -EINVAL:
		DERROR("config parameter error, input : %s\n");
		goto EXIT;
	}
	if(0 == strncmp(gloconf.cluster_name, buf, buf_prt - buf)){
		remm_info->lsv_remm_id = LSV_REMM_MASTER;	
		memcpy(remm_info->lsv_remm_remote_node_name, buf_ptr + 1, strlen(buf_ptr + 1));
	}else if(strcmp(gloconf.cluster_name, buf_ptr)){
		remm_info->lsv_remm_id = LSV_REMM_SLAVE;
		memcpy(remm_info->lsv_remm_remote_node_name, buf, buf_ptr - buf);
	}else{
		remm_info->lsv_remm_id = LSV_REMM_NONE;
		goto EXIT;
	}
	
	memset(host, 0, 256);
	if(0 != gethostname(host, 256)){
		DERROR("call gethostname failed\n");
		goto EXIT;
	}

	if(!config_lookup_string(&cfg, LSV_REMM_NODE_PAIR_STRING, &buf)){
		err = -errno;
		DERROR("config lookup LSV_REMM_ID failed\n");	
		goto EXIT;
        }
	buf_ptr = strchr(buf, ':');
	if(NULL == buf_ptr){
		err = -EINVAL:
		DERROR("config parameter error, input : %s\n");
		goto EXIT;
	}
	if(0 == strncmp(host, buf, buf_prt - buf)){
		remm_info->lsv_remm_id = LSV_REMM_MASTER;	
		memcpy(remm_info->lsv_remm_remote_node_name, buf_ptr + 1, strlen(buf_ptr + 1));
	}else if(0 == strcmp(host, buf_ptr + 1, strlen(buf_ptr + 1))){
		remm_info->lsv_remm_id = LSV_REMM_SLAVE;
		memcpy(remm_info->lsv_remm_remote_node_name, buf, buf_ptr - buf);
	}else{
		remm_info->lsv_remm_id = LSV_REMM_NONE;
		goto EXIT;
	}

#else
	/*search conf for lsv_remm_id*/
        if(!config_lookup_string(&cfg, LSV_REMM_ID_STRING, &buf)){
		err = -errno;
		DERROR("config lookup LSV_REMM_ID failed\n");	
		goto EXIT;
        }
	if(0 == strcmp("master", buf) || 0 == strcmp("MASTER", buf)){
		remm_info->lsv_remm_id = LSV_REMM_MASTER;
	}else if(0 == strcmp("slave", buf) || 0 == strcmp("SLAVE", buf)){
		remm_info->lsv_remm_id = LSV_REMM_SLAVE;
	}else{
		err = -EINVAL;
		DERROR("config lookup %s , INPUT PARAMETER ERROR, INPUT: %s\n", LSV_REMM_ID_STRING, buf);
		goto EXIT;
	}
	
	if(!config_lookup_string(&cfg, LSV_REMM_CLUSTER_NAME_STRING, &buf)){
		err = -errno;
		DERROR("config lookup LSV_REMM_ID failed\n");	
		goto EXIT;
        }
	memcpy(remm_info->lsv_remm_remote_cluster_name, buf, strlen(buf));

	if(!config_lookup_string(&cfg, LSV_REMM_NODE_NAME_STRING, &buf)){
		err = -errno;
		DERROR("config lookup LSV_REMM_ID failed\n");	
		goto EXIT;
        }
	memcpy(remm_info->lsv_remm_remote_node_name, buf, strlen(buf));


#endif
	if(!config_lookup_string(&cfg, LSV_REMM_POWER_STRING, &buf)){
		err = -errno;
		DERROR("config lookup LSV_REMM_POWER failed\n");
		goto EXIT;
	}
	if(0 == strcmp("on", buf) || 0 == strcmp("ON", buf)){
		remm_info->lsv_remm_power = LSV_REMM_POWER_ON;
	}else if(0 == strcmp("off", buf) || 0 == strcmp("OFF", buf)){
		remm_info->lsv_remm_power = LSV_REMM_POWER_OFF;
	}else{
		DERROR("config lookup %s , INVALID PARAMETER ERROR, INPUT: %s\n", LSV_REMM_POWER_STRING, buf);
		remm_info->lsv_remm_power = LSV_REMM_POWER_OFF;
	}

	if(!config_lookup_string(&cfg, LSV_REMM_MODE_STRING, &buf)){
		err = -errno;
		DERROR("config lookup LSV_REMM_MODE failed\n");
		goto	EXIT;
	}
	if(0 == strcmp("sync", buf) || 0 == strcmp("SYNC", buf)){
		remm_info->lsv_remm_mode = LSV_REMM_MODE_SYNC;
	}else if(0 == strcmp("async", buf) || 0 == strcmp("ASYNC", buf)){
		remm_info->lsv_remm_mode = LSV_REMM_MODE_ASYNC;
	}else{
		DERROR("config lookup %s , INVALID PARAMETER ERROR, INPUT: %s\n", LSV_REMM_MODE_STRING, buf);
		remm_info->lsv_remm_mode = LSV_REMM_MODE_ASYNC;
	}

	/*search conf for lsv_remm_slave_addr*/
        if(!config_lookup_string(&cfg, LSV_REMM_SLAVE_ADDR_STRING, &buf)){
		err = -errno;
		DERROR("config lookup LSV_REMM_SLAVE_ADDR failed\n");
		goto EXIT;
	}
	remm_info->lsv_remm_slave_addr = inet_network(buf);


	/*search conf for lsv_remm_slave_listen_port*/
        if(!config_lookup_int(&cfg, LSV_REMM_SLAVE_LISTEN_PORT_STRING, &data)){
		err = -errno;
		DERROR("config lookup LSV_REMM_SLAVE_LISTEN_PORT failed\n");
		goto EXIT;
        }
	remm_info->lsv_remm_slave_listen_port = data;

	volume_proto->remm_info = (void *)remm_info;
	DINFO("exit ....\n");
	goto SEC_EXIT;

EXIT:
	if(err && NULL != remm_info){
		free(remm_info);
	}
SEC_EXIT:
	config_destroy(&cfg);
        return err;
}

lsv_s32_t remm_listen(lsv_volume_proto_t *volume_proto){
	lsv_s32_t err = 0;
	lsv_remm_info *remm_info = NULL;
	struct sockaddr_in sin;	
	lsv_s32_t listen_fd = 0;

	remm_info = (lsv_remm_info *)volume_proto->remm_info;
	
	sin.sin_port = htons(remm_info->lsv_remm_slave_listen_port);
	sin.sin_addr.s_addr = htonl(INADDR_ANY);
	sin.sin_family = AF_INET;

	err = socket(AF_INET, SOCK_STREAM, 0);
	if(err < 0){
		DERROR("create socket error, err: %d\n", err);
		goto EXIT;
	}
	listen_fd = err;

	err = bind(listen_fd, (struct sockaddr *)&sin, sizeof(struct sockaddr_in));
	if(err < 0){
		DERROR("bind socket[%d] error, err: %d\n", listen_fd, err);
		goto EXIT;
	}

	err = listen(listen_fd, 65536);
	if(err < 0){
		DERROR("listen socket[%d] error, err: %d\n", listen_fd, err);
		goto EXIT;
	}	

	remm_info->listen_fd = listen_fd;

EXIT:
	return err;
}

lsv_s32_t remm_connect(lsv_volume_proto_t *volume_proto){
	lsv_s32_t err = 0;
	lsv_remm_info *remm_info = NULL;
	struct sockaddr_in sin;	
	lsv_s32_t conn_fd = 0;
	lsv_s32_t reuse = 1;
	struct timeval timeout={10, 0};
	remm_info = (lsv_remm_info *)volume_proto->remm_info;
	
	sin.sin_port = htons(remm_info->lsv_remm_slave_listen_port);
	sin.sin_addr.s_addr = htonl(remm_info->lsv_remm_slave_addr);
	sin.sin_family = AF_INET;

	err = socket(AF_INET, SOCK_STREAM, 0);
	if(err < 0){
		DERROR("create socket error, err: %d\n", err);
		goto EXIT;
	}
	conn_fd = err;
	setsockopt(conn_fd, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(struct timeval));
	setsockopt(conn_fd, SOL_SOCKET, SO_REUSEPORT, &reuse, sizeof(lsv_s32_t));

	err =connect(conn_fd, (struct sockaddr *)&sin, sizeof(struct sockaddr_in));
	if(err < 0){
		DERROR("connect to slave error, err:%d\t remote_addr: %u, remote_port: %d, sock_id: %d\n", errno, remm_info->lsv_remm_slave_addr,remm_info->lsv_remm_slave_listen_port, conn_fd);
		goto EXIT;
	} 

	remm_info->conn_fd = conn_fd;
	return conn_fd;

EXIT:
	return err;
}

lsv_s32_t remm_accept(lsv_volume_proto_t * volume_proto){
	lsv_s32_t err = 0;
	lsv_s32_t new_fd = 0;
	lsv_remm_info *remm_info = NULL;
	struct sockaddr_in remoteaddr;
	lsv_s32_t len = 0;

	remm_info = (lsv_remm_info *)volume_proto->remm_info;
	
	err = accept(remm_info->listen_fd, (struct sockaddr *)&remoteaddr, &len);
	if(err < 0){
		DERROR("accept socket failed, err: %d\n", errno);
		goto EXIT;
	}
	remm_info->conn_fd = err;
	new_fd = err;
	return new_fd;
EXIT:
	return err;
}
